/**
**************************************************************************************
*Founder Effect                                                                      *
*Copyright (C) 2006-2007, 5d Studios (www.5d-Studios.com)                            *
*                                                                                    *
*This library is free software; you can redistribute it and/or                       *
*modify it under the terms of the GNU Lesser General Public                          *
*License as published by the Free Software Foundation; either                        *
*version 2.1 of the License, or (at your option) any later version.                  *
*                                                                                    *
*This library is distributed in the hope that it will be useful,                     *
*but WITHOUT ANY WARRANTY; without even the implied warranty of                      *
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU                   *
*Lesser General Public License for more details.                                     *
*                                                                                    *
*You should have received a copy of the GNU Lesser General Public                    *
*License along with this library; if not, write to the Free Software                 *
*Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA      *
**************************************************************************************
*/
#pragma once
#include <string>
#include <map>

#include "../shared/geom.h"
#include "../shared/vector.h"
#include "../shared/EntDict.h"

#include "PhysicsObject.h"
#include "StateMachine.h"
#include "EntityController.h"


class IWeapon;
#include "Inventory.h"
/**
=============
Entity Flags 
=============
*/
enum {
    EF_UPDATE           = (1<<0),
    EF_NOTONSCREEN      = (1<<1),
    EF_MOVED            = (1<<2),
    
    /*-----------------------
        Weapon Flags
    ------------------------*/
    EF_WP_DRAWN         = (1<<3),
    EF_WP_ONGROUND      = (1<<4),

    EF_ATTACHED_TO_CAMERA = (1<<5),
    EF_NOCOLLIDE        = (1<<6),
    EF_DRAWOVER         = (1<<7)
};

/**
============================
Entity Types
============================
*/
enum EntTypes
{
    TYPE_BASE       = (1<<0),
    TYPE_ORGANISM   = (1<<1),
    TYPE_OBJECT     = (1<<2),
    TYPE_WEAPON     = (1<<3),
    TYPE_PLAYER     = (1<<4),

    TYPE_UNKNOWN=0
};

/**
=================================
Entity Base Class, all entities in
the game inherite from this.
=================================
*/
class IEntity
{

public:
    IEntity();
    IEntity(const IEntity&);
    
    /** Apply Common Dictionary Attributes */
    virtual void Apply();

    /** Get the Entity Type */
    virtual int GetType() { return TYPE_BASE; };

    /** Test if this is a player */
    virtual bool IsPlayer() {return false;};

    /** This Ents unique ID */
    unsigned int  GetID() { return m_id; };

    /** Set this Ents ID */
    void SetID(unsigned int id) { m_id = id; };

    /** This Ent is Active */
    bool IsActive() { return m_active; };

    /** Set activity */
    void SetActive(bool b) { m_active = b; };

    /** Remove the ent */
    bool CanRemove() { return m_remove; };

    /** Set the remove flag */
    void SetRemove(bool r) { m_remove = r; };

    /** Set the name */
    void SetName( const std::string &s) { m_name = s; };

    /** Get the name */
    std::string &GetName() { return m_name; };

    /** Is moveable */
    bool IsMoveable() { return m_moveable; };

    /** Set moveable */
    void SetMoveable(bool m) { m_moveable = m; };

    /** Get the Reach rectangle - creates a rect infront of entity */
    Rect GetReachRectangle();

    /** Update bounds */
    void UpdateCollisionBounds( int x, int y );

    /** Get the collision bounds */
    Rect GetBounds() { return m_bounds; };

    /** Update the entities bounds */
    void SetBounds(int x, int y, int width, int height) 
    {   m_bounds.x = x; m_bounds.y = y; 
        m_bounds.width = width; m_bounds.height = height;
    };

    /*-----------------------------------------------------------
        Entity Functionality
    ------------------------------------------------------------*/

    /** Update the entity */
    virtual void Update( long dt);
    /** Collide with another entity */
    virtual bool CollideWith( IEntity* ent ) { return false; };
	/** Damage this entity */
	virtual int Damage( int hit );
    /** Kill this entity */
    virtual void Kill() { m_health = 0; };
    /** Throws the entity */
    virtual void Throw();
    /** Attack */
    virtual void Attack();
    /** Use */
    virtual void Use();
    /** Push this entity */
    virtual void Push( IEntity* pusher );
    /** Pick Up an Item */
    virtual void PickUpItem(IEntity* ent);
    /** This entity is carrying something */
    void Carry( IEntity* ent );
    /** Carried By */
    void Carrier( IEntity* ent ) { m_carrier = ent; };
    /** Who is carrying this entity */
    IEntity* CarriedBy() { return m_carrier; };
    /** Test to see if this ent is carrying an entity */
    bool CarryingEntity() { return m_carriedEntity != NULL; }

    /*----------------------------------------------------------
        Representation
    ------------------------------------------------------------*/
    /** Get the face direction */
    int GetFace() { return m_face; };
    /** Set the direction */
    void SetFace( int f);

    /** Set the active state */
    void SetState(const std::string &state) { m_FSM.ChangeState( m_states[state] ); };
    /** Get the current state */
    std::string GetState() { return m_FSM.GetCurrentState() ? m_FSM.GetCurrentState()->GetStateType() : "IDLE"; };
    /** Get the current state integer value */
    int         GetIntState() { return m_FSM.GetCurrentState() ? m_FSM.GetCurrentState()->GetType() : IDLE; };

    /** Add a state */
    void AddState(const std::string &state, State* s) 
    { m_states[state] = s;
    };

    /** Move this ent NOW */
    virtual bool MoveTo( const Vector2f &dest ) 
    { 
        m_physObject.SetPosition( dest );
        m_flags |= EF_MOVED;

        UpdateCollisionBounds( dest.x, dest.y );
        return false; 
    };

    /** Move the entity for amount time in the dest direction */
    virtual void MoveToOverTime( const Vector2f &direction, float time ) 
    {
        m_vDirection = direction;
        m_moveTime = time;
    };

    /** Arrived to location */
    bool ArrivedToLocation(); 

    PhysicsObject   m_physObject;           // Do translations 
    Vector2f        m_vForward;             // forward vector
    Vector2f        m_vDirection;           // Direction
    Vector2f        m_vDestination;         // destination point 


    float           m_fSpeed;               // Walk Speed
    float           m_fThrowSpeed;          // Throw Speed
    float           m_fPushSpeed;           // Push Speed
    float           m_heightAboveGround;    // height above ground
    float           m_fGravity;             // gravity NOTE: NOT a constant, because certain entities may need a different effect
    
	int				m_health;               // health
    int             m_flags;                // Entity flags


    
    EntDict         m_attributes;           // Dictionary of attributes

    
    Inventory<IEntity*>     m_itemInventory;        // items inventory
    Inventory<IWeapon*>     m_weaponInventory;      // weapons inventory

    
    int             m_actions;              // action received from the controller
    float           m_nextUpdate;           // the entities next update

    virtual ~IEntity();
protected:
    /** Dis/Enable user input */
    void EnableInput( bool b ) { m_readInput = b; };
    /** Test to see if this ent should receive input events */
    bool InputEnabled() { return m_readInput; };

    /** Check the face of the entity */
    void CheckFace(int action);
    /** Check to see if the ent is pushing */
    void CheckPush();
    /** Check for movement */
    void CheckMove();
    /** Check for attacking */
    bool CheckAttack();
    /** Check for use */
    bool CheckUse();

    /** Check for weapon change */
    void CheckWeaponChange();

   
    unsigned int        m_id;               // id
    std::string         m_name;             // name of entity
    bool                m_remove;           // remove flag
    bool                m_active;           // activity
        
    Rect                m_bounds;           // Collision bound
    
    int                 m_face;             // Direction facing
    int                 m_oldFace;          // old face
    
    IEntity*            m_carriedEntity;    // entity being carried
    IEntity*            m_carrier;          // entity doing the carring
	

    Vector2f            m_vThrowVelocity;
    float               m_moveTime;         // time to move in a given direction

    
    Vector2f            m_vOldPosition;     // old position - used for pushing objects
    float               m_fPushWaitTime;    // Time to wait until we can push
    bool                m_moveable;         // if this entity is moveable
    

    StateMachine        m_FSM;              // State Machine
    EntityController    m_entCtrl;          // Entity controller - capture events
    bool                m_readInput;        // if this entity should
                                            // receive input

    float               m_weaponChangeTime; // TEMP -- Amount of time between weapon changes
	
    typedef std::map<std::string , State*> type_States;     
    type_States         m_states;                           // state list

    // friends
    friend State;
    friend EntityController;

};
